using System;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests
{
    public class RequiredRuleTest
    {


        const string expectedErrorMessage = "expectedErrorMessage";
        const string expectedRuleSet = "EXPECTEDRULESET";
        const int expectedInitialValue = 3;
        [TestFixture]
        public class Construction
        {
            [Test]
            public void Simple1()
            {
                var rule = new RequiredRule<int>();
            }

            [Test]
            public void Simple2()
            {
                var rule = new RequiredRule<int>
                           	{
                           		InitialValue = expectedInitialValue
                           	};
                Assert.AreEqual(expectedInitialValue, rule.InitialValue);
            }


            [Test]
            public void Simple3()
            {
                var rule = new RequiredRule<int>();
            }


            [Test]
            public void Simple4()
            {
                var rule = new RequiredRule<int>();
                Assert.IsNull(rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);

            }
        }
        [TestFixture]
        public class IsEquivalent
        {
            [Test]
            public void Simple()
            {
                var rule1 = new RequiredRule<int>();
                var rule2 = new RequiredRule<int>();
                Assert.IsTrue(rule1.IsEquivalent(rule2));

                rule1 = new RequiredRule<int>
                        	{
                        		InitialValue = 1
                        	};
				rule2 = new RequiredRule<int>
				{
					InitialValue = 1
				};
                Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new RequiredRule<int>
				{
					InitialValue = 1
				};
				rule2 = new RequiredRule<int>
				{
					InitialValue = 2
				};
                Assert.IsFalse(rule1.IsEquivalent(rule2));

                rule1 = new RequiredRule<int>();
				rule2 = new RequiredRule<int>
				{
					InitialValue = 1
				};
                Assert.IsFalse(rule1.IsEquivalent(rule2));
            }
        }
        [TestFixture]
        public class GetComputedErrorMessage
        {

            [Test]
            public void ErrorMessage()
            {
                var rule1 = new RequiredRule<int>();
                var returnValue1 = ReflectionUtilities.CallMethod<RequiredRule<int>>(rule1, "GetComputedErrorMessage", "foo", "testMemberType");
				Assert.AreEqual("The testMemberType 'foo' is required and cannot be '0'.", returnValue1);

				var rule2 = new RequiredRule<int>
				{
					InitialValue = 2
				};
                var returnValue2 = ReflectionUtilities.CallMethod<RequiredRule<int>>(rule2, "GetComputedErrorMessage", "foo", "testMemberType");
                Assert.AreEqual("The testMemberType 'foo' is required and cannot be '2'.", returnValue2);
            }
        }

        [TestFixture]
        public class Validate
        {
            [Test]
            public void Nullable()
            {
                var rule1 = new RequiredRule<int>();
                rule1.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));
                Assert.IsFalse(rule1.Validate(null, null, null, null));
                Assert.IsTrue(rule1.Validate(null, 4, null, null));
                Assert.IsTrue(rule1.Validate(null, 0, null, null));

				var rule2 = new RequiredRule<int>
				{
					InitialValue = 1
				};
                rule2.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));
                Assert.IsFalse(rule2.Validate(null, 2, null, null));
                Assert.IsTrue(rule2.Validate(null, 4, null, null));
                Assert.IsTrue(rule2.Validate(null, null, null, null));
                Assert.IsTrue(rule2.Validate(null, 0, null, null));

            }
            [Test]
            public void NotNullable()
            {
                var rule = new RequiredRule<int>();
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsFalse(rule.Validate(null, default(int), null, null));
                Assert.IsTrue(rule.Validate(null, 4, null, null));

				var rule2 = new RequiredRule<int>
				{
					InitialValue = 2
				};
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsFalse(rule2.Validate(null, 2, null, null));
                Assert.IsTrue(rule2.Validate(null, 4, null, null));

            }

        }
        [TestFixture]
        public class RuleInterpretation
        {
            [Test]
            public void Simple()
            {
                var rule1 = new RequiredRule<int>();
                Assert.AreEqual("The value must not be '0'.", rule1.RuleInterpretation);

				var rule2 = new RequiredRule<int>
				{
					InitialValue = 2
				};
                Assert.AreEqual("The value must not be '2'.", rule2.RuleInterpretation);
            }
            [Test]
            public void NullInitialValue()
            {
                var rule = new RequiredRule<int>();
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsNotNull(rule.RuleInterpretation);
            }


            [Test]
            public void NotNullInitialValue()
            {
				var rule = new RequiredRule<int>
				{
					InitialValue = 2
				};
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsNotNull(rule.RuleInterpretation);
            }
        }



        [TestFixture]
        public class CheckTypes
        {
            [Test]
            public void Simple()
            {
                var structRule = new RequiredRule<int>();
                structRule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                var nullableRule = new RequiredRule<int>();
                nullableRule.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.Int32' to be used for the ValidationFramework.RequiredRule<System.Int32>. Actual Type 'System.String'.\r\nParameter name: value")]
            public void ExceptionInvalidType()
            {
                var rule = new RequiredRule<int>();
                rule.CheckType(new MockInfoDescriptor(typeof (string).TypeHandle, "foo"));
            }
        }

    }
}